package pl.edu.agh.mobsys.utils;

import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.PacketExtension;

import pl.edu.agh.mobsys.utils.Constants.SmoaAgentType;

import android.util.Log;

public class SmoaParser {

	public static final String SOAP_ELEMENT_NAME_1 = "Envelope";
	public static final String SOAP_ELEMENT_NAME_2 = "SOAP-ENV:Envelope";
	public static final String SOAP_NAMESPACE = "http://www.w3.org/2003/05/soap-envelope";

	private static final String TAG = "SmoaParser";

	public static enum MessageType {
		SubscribeConfirmation, ResubscribeConfirmation, UnsubscribeConfirmation, AddJobConfirmation, JobStatusUpdate, CancelJobConfirmation, Fault, Unrecognised
	};

	public static class ParsedMessage {
		public final Constants.SmoaAgentType agentType;
		public final MessageType messageType;
		public final String id;
		public final String info;

		public ParsedMessage(Constants.SmoaAgentType agentType,
				MessageType messageType, String id, String info) {
			this.agentType = agentType;
			this.messageType = messageType;
			this.id = id;
			this.info = info;
		}
	};

	public static ParsedMessage parseMessage(Packet packet,
			String notifierAgentName, String jobReceiverAgentName) {

		String messageText = null;

		for (PacketExtension pe : packet.getExtensions()) {
			if (pe.getElementName().equals(SOAP_ELEMENT_NAME_1)
					|| pe.getElementName().equals(SOAP_ELEMENT_NAME_2)) {
				messageText = pe.toXML();
				break;
			}
		}

		Log.d(TAG, notifierAgentName + " " + jobReceiverAgentName);

		SmoaAgentType agentType = null;
		if (messageText.indexOf(notifierAgentName) != -1) {
			agentType = SmoaAgentType.NOTIFIER;
		} else if (messageText.indexOf(jobReceiverAgentName) != -1) {
			agentType = SmoaAgentType.JOB_RECEIVER;
		} /*
		 * else { Log.d(TAG, notifierAgentName + " & " + jobReceiverAgentName +
		 * " not found in" + messageText); return new ParsedMessage(agentType,
		 * null, "?", "?"); }
		 */

		Log.i(TAG, "Parsing packet with inner message: " + messageText);

		if (messageText.indexOf("SubscribeRequest") != -1) {
			String subscriptionID = find(messageText, "SubscriptionID");
			return new ParsedMessage(agentType,
					MessageType.SubscribeConfirmation, subscriptionID, "");
		}
		if (messageText.indexOf("RenewResponse") != -1) {
			String subscriptionId = find(messageText, "wsa5:MessageID", ":");
			return new ParsedMessage(agentType,
					MessageType.ResubscribeConfirmation, subscriptionId, "");
		}
		if (messageText.indexOf("UnsubscribeResponse") != -1) {
			String subscriptionId = find(messageText, "wsa5:MessageID");
			return new ParsedMessage(agentType,
					MessageType.UnsubscribeConfirmation, subscriptionId, "");
		}
		if (messageText.indexOf("CreateActivityResponse") != -1) {
			// String state = find(messageText, "Status");
			String id = find(messageText, "smoa-comp-factory:ActivityId", ":");
			return new ParsedMessage(agentType, MessageType.AddJobConfirmation,
					id, "");
		}
		if (messageText.indexOf("Terminated") != -1) {
			String id = find(messageText, "smoa-comp-factory:ActivityId", ":");
			return new ParsedMessage(agentType,
					MessageType.CancelJobConfirmation, id, "");
		}
		if (messageText.indexOf("GetActivityStatusesResponse") != -1) {
			String id = find(messageText, "smoa-comp-factory:ActivityId", ":");
			int st = messageText.indexOf("state='") + 7;
			int fn = st;
			while (fn < messageText.length() && messageText.charAt(fn) != '\'') {
				fn++;
			}
			String state = new String(messageText.substring(st, fn));
			return new ParsedMessage(agentType, MessageType.JobStatusUpdate,
					id, state);
		}
		if (messageText.indexOf("Status") != -1) {
			String state = find(messageText, "Status");
			String id = find(messageText, "ActivityId");
			return new ParsedMessage(agentType, MessageType.JobStatusUpdate,
					id, state);
		}
		if (messageText.indexOf("fault") != -1) {
			return new ParsedMessage(agentType, MessageType.Fault, "", "");
		}
		return new ParsedMessage(agentType, MessageType.Unrecognised, "",
				messageText);
	}

	private static String find(String message, String tag) {
		// int st = message.indexOf("<" + tag + ">") + tag.length() + 2;
		int fn = message.lastIndexOf("</" + tag + ">");
		if (fn != -1) {
			int st = fn;
			while (st >= 0 && message.charAt(st) != '>') {
				st--;
			}
			st++;
			return new String(message.substring(st, fn));
		} else {
			return "Failed to find";
		}
	}

	private static String find(String message, String tag, String beginSymbol) {
		String found = find(message, tag);
		int st = found.lastIndexOf(beginSymbol);
		if (st != -1) {
			return new String(found.substring(st + 1));
		}
		return "Failed to find beginSymbol";
	}

	private static final PacketFilter pf = new PacketFilter() {
		public boolean accept(Packet packet) {
			for (PacketExtension pe : packet.getExtensions()) {
				if (pe.getElementName().equals(SmoaParser.SOAP_ELEMENT_NAME_1)
						|| pe.getElementName().equals(SOAP_ELEMENT_NAME_2)) {
					return true;
				}
			}
			return false;
		}
	};

	public static PacketFilter getSmoaPacketFilter() {
		return pf;
	}
}
